package handle

import (
	"github.com/hwcer/cosgo/registry"
	"github.com/hwcer/updater/dataset"
	"github.com/hwcer/yyds/context"
	"github.com/hwcer/yyds/errors"
	"github.com/hwcer/yyds/players/verify"
	"server/game/cache"

	"server/game/model"
	"server/share/config"
)

func init() {
	Register(&Task{})
}

type Task struct {
}

func (this *Task) Caller(node *registry.Node, c *context.Context) interface{} {
	f := node.Method().(func(*Task, *context.Context) interface{})
	return f(this, c)
}

type TaskValueArg struct {
	Condition int32   `json:"condition"`
	Key       int32   `json:"key"`  //任务参数
	Args      []int32 `json:"args"` //附加参数
}

func (tv *TaskValueArg) GetCondition() int32 {
	return tv.Condition
}
func (tv *TaskValueArg) GetKey() int32 {
	return tv.Key
}
func (tv *TaskValueArg) GetArgs() []int32 {
	return tv.Args
}

// Value 查询任务条件的当前值
func (*Task) Value(c *context.Context) interface{} {
	args := &TaskValueArg{}
	if err := c.Bind(args); err != nil {
		return err
	}
	c.Player.Verify.Target(args)
	if err := c.Player.Data(); err != nil {
		return err
	}
	return c.Player.Verify.Value(args)
}

// Accept 接任务，仅限于即时任务
// id int32 任务ID
func (*Task) Accept(c *context.Context) interface{} {
	id := c.GetInt32("id")
	if id == 0 {
		return errors.ErrArgEmpty
	}
	cfg := config.Data.Task[id]
	if cfg == nil {
		return errors.ErrConfigEmpty
	}
	if cfg.Accept == 0 {
		return errors.Errorf(0, "task accept error")
	}
	if cfg.Accept > 1 {
		//return false
	}

	role := c.Player.Document(config.ITypeRole).Any().(*model.Role)
	if role.Lv < cfg.Ulv {
		return c.Error("task ulv limit")
	}
	handle := cache.GetTask(c.Player.Updater)
	//添加记录
	handle.Select(id)
	//前置任务
	handle.Auto(cfg.Limit...)
	if err := c.Player.Data(); err != nil {
		return err
	}
	//检查是否已经存在任务
	data, _ := handle.GetOrCreate(c.Player.Updater, id)
	data.MayRefresh(c.Unix())
	if data.Status == model.TaskStatusComplete {
		return errors.ErrDataExists
	}

	expire, err := c.Player.Times.ExpireWithArray(cfg.Expire...)
	if err != nil {
		return err
	}
	d := dataset.Update{"val": data.Value, "expire": expire, "status": model.TaskStatusNone}
	handle.Update(id, d)
	return nil
}

// Submit 提交任务，数据获取，只针对 成就任务，主线任务等，不包含日常，每周，bp任务
func (*Task) Submit(c *context.Context) interface{} {
	id := c.GetInt32("id")
	if id == 0 {
		return errors.ErrArgEmpty
	}
	cfg := config.Data.Task[id]
	if cfg == nil {
		return errors.ErrConfigEmpty
	}
	handle := cache.GetTask(c.Player.Updater)

	//等级限制
	role := c.Player.Document(config.ITypeRole).Any().(*model.Role)
	if role.Lv < cfg.Ulv {
		return c.Error("task ulv limit")
	}
	//添加记录
	handle.Select(id)
	//前置任务
	handle.Auto(cfg.Limit...)
	target := NewTaskTarget(cfg)
	c.Player.Verify.Auto(target)
	//添加道具
	c.Player.AddItems(cfg.Item)
	if err := c.Player.Data(); err != nil {
		return err
	}
	//检查是否已经完成任务
	data, loader := handle.GetOrCreate(c.Player.Updater, id)
	if !loader && cfg.Accept > 0 {
		return c.Error("task not exist")
	}
	if data.Status == model.TaskStatusComplete {
		return errors.ErrDataExists
	}

	target.val = data.Value
	target.times = [2]int64{data.Value, data.Expire}

	update := dataset.Update{"status": model.TaskStatusComplete}
	update["submit"] = data.Submit + 1
	if expire, err := c.Player.Times.ExpireWithArray(cfg.Expire...); err != nil {
		return err
	} else {
		update["expire"] = expire
	}
	handle.Update(id, update)
	c.Player.Emit(config.Data.Events.TaskSubmit, id)
	_ = handle.Accept(cfg.Next...)
	//事件
	if es := cfg.Events; len(es) > 0 {
		for _, e := range es {
			c.Player.Emit(e, 1)
		}
	}

	return true
}

// Delete 删除任务，只能删除未完成的任务
func (*Task) Delete(c *context.Context) interface{} {
	id := c.GetInt32("id")
	if id == 0 {
		return errors.ErrArgEmpty
	}
	cfg := config.Data.Task[id]
	if cfg == nil {
		return errors.ErrConfigEmpty
	}
	if cfg.Accept == 0 {
		return false
	}
	handle := cache.GetTask(c.Player.Updater)
	//添加记录
	handle.Select(id)
	if err := c.Player.Data(); err != nil {
		return err
	}
	//检查是否已经存在任务
	data := handle.Get(id)
	if data == nil || data.Status != model.TaskStatusNone {
		return false
	}
	handle.Del(data.OID)
	return true
}

func NewTaskTarget(target verify.Target) *TaskTarget {
	return &TaskTarget{Target: target}
}

type TaskTarget struct {
	verify.Target
	val   int64
	times [2]int64
}

func (t *TaskTarget) GetVal() int64 {
	return t.val
}

func (t *TaskTarget) GetTimes() [2]int64 {
	return t.times
}
